<?php

/**
 * @package     project
 */

/**
 * @author      wellington
 * @package     project
 * @created     04/09/2013
 * @version     $Id$
 */
class Entidade_Model_GeradorClasse {

  public function getEntity($noTabela) {

    $conexaoDB = new Entidade_Model_ConexaoDB('sqlserver');
    $colunas = $conexaoDB->getListaColuna($noTabela);

    $aChavePrimaria = $conexaoDB->getPkColuna($noTabela);

    $arrProp = array();
    $arrMetodo = array();
    $validator = '';
    
    if (strpos($noTabela, 'vw') > 0) {
      
      $delimitador = ( count(substr($noTabela, 2)) > 4 ) ? 5 : $delimitador;
    } else {
      
      $delimitador = 5;
    }
    
    foreach ($colunas as $coluna) {
      
      if (strtolower(trim($coluna['IS_NULLABLE'])) == "no" ) {
        $validator .= "\$this->oValidator->addElement('" . substr($coluna['COLUMN_NAME'], $delimitador) . "')
       ->blank('E/msg.obrigatorio');\n"; 
      }      
    }
    
    $arrMetodo[] = // Method passed as array
      array(
        'name' => '__construct',
        'body' => '// chama o construtor da classe pai antes de declarar os validadores' . "\n"
        . 'parent::__construct();'. "\n\n" .
        $validator
      );

    foreach ($colunas as $coluna) {

      $exibeId = '';
      $noAtributo = '';
      
      foreach ($aChavePrimaria as $sChavePrimaria) {
        
        if ($coluna['COLUMN_NAME'] == $sChavePrimaria['COLUMN_NAME']) {

          $noAtributo = count($aChavePrimaria) > 1 ? substr($coluna['COLUMN_NAME'], $delimitador) : 'Id';
          $exibeId = "     * @Id\n     * @GeneratedValue\n";
        }      
      }

      $this->retornaTipo($coluna['DATA_TYPE']);
      $nullable = ( strtolower(trim($coluna['IS_NULLABLE'])) == "no" ) ? ", nullable=false" : ", nullable=true";
      $length = ( $coluna['CHARACTER_MAXIMUM_LENGTH'] ) ? ", length=" . $coluna['CHARACTER_MAXIMUM_LENGTH'] : '';

      if ($noAtributo != "Id") {
        
        $noAtributo = substr($coluna['COLUMN_NAME'], $delimitador);
      }

      $arrProp[] = array(
        'name' => $this->prefixo . $noAtributo,
        'visibility' => "/**\n" . $exibeId .
        "     * @Column(name=\"" . $coluna['COLUMN_NAME'] .
        "\", type=\"" . $this->tipo .
        "\"" . $length .
        $nullable . ")\n" .
        "     */\n" .
        "     private"
      );

      $arrMetodo[] = // Method passed as array
        array(
          'name' => 'set' . ucfirst($noAtributo),
          'parameters' => array(
            array('name' => $this->prefixo . $noAtributo),
          ),
          'body' => '$this->' . $this->prefixo . $noAtributo . ' = $' . $this->prefixo . $noAtributo . ';' . "\n"
      );


      $arrMetodo[] = // Method passed as concrete instance
        array(
          'name' => 'get' . ucfirst($noAtributo),
          'body' => 'return $this->' . $this->prefixo . $noAtributo . ';',
      );
    }

    return $this->setClasseEntity($noTabela, $arrProp, $arrMetodo);
  }
  
  public function getModel( $noTabela ) {

    $arrProp = array();
    $arrMetodo = array();

    $arrProp[] = array(
      'name' => 'oEM',
      'visibility' => "/**\n" .
      "     * @var \Doctrine\ORM\EntityManager The created EntityManager.\n" .        
      "     */\n" .
      "     private"
    );

    $arrProp[] = array(
      'name' => 'oRepository',
      'visibility' => "/**\n" .
      "     * @var Entity\\repository\\" . $noTabela . "Repository\n" .        
      "     */\n" .
      "     private"
    );

    $arrMetodo[] = // Method passed as array
      array(
      'name' => 'getEntityManager',          
      'body' => 'if (is_null($this->oEM)) {' . "\n" .
        '$this->oEM = FwEntityManager::getInstance(\'sigeo\')->getDoctrineEntityManager();' . "\n" .
        '}' . "\n"
      );

    $arrMetodo[] = // Method passed as array
      array(
      'name' => 'getRepository',          
      'body' => 'if (is_null($this->oRepository)) {' . "\n" .
        '$this->oRepository = $this->getEntityManager()->getRepository(' . "\n" .
        '\'\\' . Zend_Registry::get('config')->db->module . '\\models\\entity\\' . $noTabela . '\');' . "\n" .
        '}' . "\n" .
        'return $this->oRepository;' . "\n"           
      );

    $arrMetodo[] = // Method passed as array
      array(
      'name' => 'obter' . $noTabela,   
      'parameters' => array(
          array('name' => 'o' . $noTabela),
      ),
      'body' => 'return $this->getRepository()->find($o' . $noTabela . ');' . "\n"
      );

    $arrMetodo[] = // Method passed as array
      array(
      'name' => 'listar' . $noTabela,          
      'parameters' => array (
          array (
            'name' => 'oQryObject',
            'type' => '\\fwQueryObject',
            'defaultValue' => 'NULL'              
          )
      ),
      'body' => '$aWhere = array();' . "\n" . 
        'return $this->getRepository()->findBy($aWhere, array());' . "\n"
      );

     $arrMetodo[] = // Method passed as array
      array(
      'name' => 'obterRelacao',          
      'parameters' => array (
          array (
            'name' => 'oQryObject',
            'type' => '\\fwQueryObject'             
          ),
          array (
            'name' => 'iQuantidadeRegistro'                
          ),
          array (
            'name' => 'oIniConstants'             
          )
       ),
      'body' => 'return $this->getRepository()->obterRelacao($oQryObject, $iQuantidadeRegistro, $oIniConstants);'          
      );

    return $this->setClasseModel($noTabela, $arrProp, $arrMetodo);
  }
  
  public function getRepository($noTabela) {

    
    $arrProp = array();
    $arrMetodo = array();
    
    return $this->setClasseRepository($noTabela, $arrProp, $arrMetodo);
  }

  public function retornaTipo($tipo) {

    switch ($tipo) {
      case 'int':
        $this->tipo = "integer";
        $this->prefixo = "i";
        break;
      case 'varchar':
        $this->tipo = "string";
        $this->prefixo = "s";
        break;
      case 'bit':
        $this->tipo = "boolean";
        $this->prefixo = "b";
        break;
      case 'char':
        $this->tipo = "string";
        $this->prefixo = "s";
        break;
      case 'tinyint':
        $this->tipo = "integer";
        $this->prefixo = "i";
        break;
      case 'money':
        $this->tipo = "decimal";
        $this->prefixo = "f";
        break;
      default:
        $this->tipo = $tipo;
        $this->prefixo = $tipo[0];
        break;
    }
  }
  
  /**
   * @param type $noClasse
   * @param type $arrProp
   * @param type $arrMetodo
   * @return \Zend_CodeGenerator_Php_Class
   */
  public function setClasseEntity($noClasse, $arrProp, $arrMetodo) {

    $classe = new Zend_CodeGenerator_Php_Class();
    $docblock = new Zend_CodeGenerator_Php_Docblock(array(
      'shortDescription' => 'Classe Gerada para entidade ' . $noClasse,
      'tags' => array(
        array(
          'name' => 'Table',
          'description' => '(name="' . Zend_Registry::get('config')->db->dbname . ".dbo." . $noClasse . '")',
        ),
        array(
          'name' => 'Entity',
          'description' => "(repositoryClass=\"" . Zend_Registry::get('config')->db->module . "\\models\\entity\\repository\\" . $noClasse . "Repository\")",
        ),
        array(
          'name' => 'HasLifecycleCallbacks',
          'description' => "",
        )
      ),
    ));

    $classe->setName($noClasse)
      ->setExtendedClass('\fw\fwEntity')
      ->setDocblock($docblock)
      ->setProperties($arrProp)
      ->setMethods($arrMetodo);

    return $classe;
  }
  
  /**
   * 
   * @param type $noClasse
   * @param type $arrProp
   * @param type $arrMetodo
   * @return \Zend_CodeGenerator_Php_Class
   */
  public function setClasseModel($noClasse, $arrProp, $arrMetodo) {

    $classe = new Zend_CodeGenerator_Php_Class();
    $docblock = new Zend_CodeGenerator_Php_Docblock(array(
      'shortDescription' => 'Model da entidade ' . $noClasse      
    ));

    $classe->setName($noClasse . 'Model')
      ->setDocblock($docblock)
      ->setProperties($arrProp)
      ->setMethods($arrMetodo);

    return $classe;
  }
  
  /**
   * 
   * @param type $noClasse
   * @param type $arrProp
   * @param type $arrMetodo
   * @return \Zend_CodeGenerator_Php_Class
   */
  public function setClasseRepository ($noClasse, $arrProp, $arrMetodo) {

    $classe = new Zend_CodeGenerator_Php_Class();
    $docblock = new Zend_CodeGenerator_Php_Docblock(array(
      'shortDescription' => 'Repository da entidade ' . $noClasse      
    ));

    $classe->setName($noClasse . 'Repository')
      ->setExtendedClass('EntityRepository')
      ->setDocblock($docblock)
      ->setProperties($arrProp)
      ->setMethods($arrMetodo);

    return $classe;
  }

}
